﻿/*
 * SVN-based CodeReview
 * Copyright (c) Karim Agha <karim.dev@gmail.com>.
 */

namespace Sentio.CodeReview.Foundation
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;

    /// <summary>
    /// A target is anything that could be a contaner for comments, usually source code files are
    /// a good candidate to be targets, comments could also be added to folders though.
    /// </summary>
    public class Target
    {
        protected readonly List<BlockComment> _comments = null;
        protected readonly List<Target> _childTargets = null;

        /// <summary>
        /// The read-only collection of comments bound to this current target.
        /// </summary>
        public ReadOnlyCollection<BlockComment> Comments
        {
            get
            {
                return _comments.AsReadOnly();
            }
        }


        /// <summary>
        /// A relative path to the file or directory that is the current target.
        /// </summary>
        public string TargetPath { get; protected set; }

        /// <summary>
        /// A collection of comments for this target that require some attention.
        /// Comments flagged with LGTM, Abandoned are not a concern for most of the times.
        /// </summary>
        public ReadOnlyCollection<BlockComment> RelevantComments
        {
            get
            {
                return new ReadOnlyCollection<BlockComment>(_comments.Where(c => c.Status != BlockCommentStatus.Positive ||
                                                                                 c.Status != BlockCommentStatus.Abandoned).ToList());
            }
        }

        /// <summary>
        /// A collection of child targets. Typically this is an empty collection for
        /// code files and for directories, it contains a list of files and directories inside that 
        /// directory.
        /// </summary>
        /// <remarks>
        /// When the returned value is null, it does not nesseserly mean that it has no child nodes. 
        /// In that case, it might happen that the childTargets are just not iterated through.
        /// </remarks>
        public IEnumerable<Target> ChildTargets
        {
            get
            {
                if (ChildTargets != null)
                {
                    return _childTargets.AsReadOnly();
                }
                return null;
            }
        }

        /// <summary>
        /// Instantiate a target without any existing comment.
        /// </summary>
        /// <param name="path"></param>
        public Target(string path)
            :this(path, new BlockComment[] {})
        {

        }

        /// <summary>
        /// Instantiate a target with a collection of existing comments.
        /// </summary>
        /// <param name="comments"></param>
        public Target(string path, IEnumerable<BlockComment> comments)
        {
            if(string.IsNullOrWhiteSpace(path))
            {
                throw new ArgumentNullException("path");
            }
            
            if(comments == null)
            {
                throw new ArgumentNullException("comments");
            }

            _comments = new List<BlockComment>(comments);
            TargetPath = path;
        }
    }
}
